/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package liftsimulator;

import Interface.FloorUI;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 *
 * @author James Barker
 */
public class Building extends JFrame implements ActionListener, Runnable {

    final int FLOOR_HEIGHT = 50;
    final int IN_QUEUE_WIDTH = 250;
    final int SHAFT_WIDTH = 50;
    final int OUT_QUEUE_WIDTH = 250;
    final int FLOOR_UI_WIDTH = 50;
    public int noFloors;
    public int noLifts;
    ArrayList<QueueIn> inQueue;
    LiftShaft[] shafts;
    ArrayList<QueueOut> outQueue;
    ArrayList<FloorUI> floors;
    ArrayList<Person> waitingList1 = new ArrayList<Person>();
    ArrayList<Person> waitingList2 = new ArrayList<Person>();
    ArrayList<Person> waitingList3 = new ArrayList<Person>();
    JPanel inQueuePanel;
    JPanel shaftPanel;
    JPanel outQueuePanel;
    JPanel floorPanel;
    int addPersonPrabability;
    int simulationTimerSeconds;
    public int k;
    public int tempK;
    public int counter;
    public boolean alarmFlag = false;
    public LiftShaft ls;
    public String region;
    public String liftColour;
    public String liftShaftColour;
    public ArrayList<ElevatorUI> euiList;
    List<String> peopleOnLiftArray = new ArrayList<String>();
    ElevatorUI eui;

    public Building(int noLifts, int noFloors, String region, String liftColour, String liftShaftColour) {
        this.noLifts = noLifts;
        this.noFloors = noFloors;
        this.region = region;
        this.liftColour = liftColour;
        this.liftShaftColour = liftShaftColour;
        this.setLayout(new GridBagLayout());

        //System.out.println("EUIList slot 0 = " + .get(0));
        createInQueuePanel();
        createShaftPanel();
        createOutQueuePanel();
        createFloorPanel();

        this.setTitle("Simulation Interface");
        this.setLocation(308, 320);
        this.setSize(new Dimension(750, (noFloors * FLOOR_HEIGHT + 50)));
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }

    public void createInQueuePanel() {
        inQueue = new ArrayList<QueueIn>();
        inQueuePanel = new JPanel();
        inQueuePanel.setLayout(new GridLayout(noFloors, 1));

        for (int i = noFloors; i >= 1; i--) {
            inQueue.add(0, new QueueIn(i, IN_QUEUE_WIDTH, FLOOR_HEIGHT));
            inQueuePanel.add(inQueue.get(0));
            //new Thread(inQueue.get(0)).start();
        }
        this.add(inQueuePanel);
    }

    public void createShaftPanel() {
        shafts = new LiftShaft[noLifts];
        shaftPanel = new JPanel();
        shaftPanel.setLayout(new GridLayout(1, noLifts));

        for (int i = 1; i <= noLifts; i++) {
            ls = new LiftShaft(i, noFloors, SHAFT_WIDTH, FLOOR_HEIGHT, this);
            shafts[i - 1] = ls;
            shaftPanel.add(shafts[i - 1]);
            this.add(shaftPanel);
            new Thread(shafts[i - 1]).start();
        }


    }

    public void createOutQueuePanel() {
        outQueue = new ArrayList<QueueOut>();
        outQueuePanel = new JPanel();
        outQueuePanel.setLayout(new GridLayout(noFloors, 1));

        for (int i = noFloors; i >= 1; i--) {
            outQueue.add(0, new QueueOut(i, OUT_QUEUE_WIDTH, FLOOR_HEIGHT));
            outQueuePanel.add(outQueue.get(0));
            //new Thread(inQueue.get(0)).start();
        }
        this.add(outQueuePanel);
    }

    public void createFloorPanel() {
        floors = new ArrayList<FloorUI>();
        floorPanel = new JPanel();
        floorPanel.setLayout(new GridLayout(noFloors, 1));
        if (region == "AUS/UK") {
            for (int i = noFloors - 1; i >= 0; i--) {
                if (i == 0) {
                    floors.add(0, new FloorUI("G", FLOOR_UI_WIDTH, FLOOR_HEIGHT));
                    floorPanel.add(floors.get(0));
                } else {
                    floors.add(0, new FloorUI(Integer.toString(i), FLOOR_UI_WIDTH, FLOOR_HEIGHT));
                    floorPanel.add(floors.get(0));
                }
            }
        } else {
            for (int i = noFloors; i >= 1; i--) {
                floors.add(0, new FloorUI(Integer.toString(i), FLOOR_UI_WIDTH, FLOOR_HEIGHT));
                floorPanel.add(floors.get(0));

            }
        }
        floorPanel.setVisible(true);
        this.add(floorPanel);
    }

    public void setAddPersonPrabability(int addPersonPrabability) {
        if (noLifts == 1) {
            this.addPersonPrabability = addPersonPrabability / 2;
        }
        if (noLifts == 2) {
            this.addPersonPrabability = addPersonPrabability / 3;
        }
        if (noLifts == 3) {
            this.addPersonPrabability = addPersonPrabability / 4;
        }

    }

    public void setSimulationTimerSeconds(int simulationTimerSeconds) {
        this.simulationTimerSeconds = simulationTimerSeconds;
    }

    public void manualAddPersonToLift(int id, int desiredFloor) {
        int startFloor = ls.getLiftFloor();
        int destFloor = desiredFloor;
        //Create Person and set attributes
        Person zzz = new Person(startFloor, destFloor);
        zzz.genSetUserID();
        zzz.setStatus("TRAV");

        if (id == 1) {
            waitingList1.add(zzz);
            euiList.get(0).addIDToStringArray(zzz.getId(), zzz.getDestFloor());
            euiList.get(0).updateUsersOnLiftPanel();
            System.out.println("-------------------------------------------");
            System.out.println("getDirection() = " + zzz.getDirection());
            System.out.println("getId() = " + zzz.getId());
            System.out.println("getStatus() = " + zzz.getStatus());
            System.out.println("getStartFloor() = " + zzz.getStartFloor());
            System.out.println("getDestFloor() = " + zzz.getDestFloor());
            System.out.println("-------------------------------------------");
        }
        if (id == 2) {
            waitingList2.add(zzz);
            euiList.get(1).addIDToStringArray(zzz.getId(), zzz.getDestFloor());
            euiList.get(1).updateUsersOnLiftPanel();
            System.out.println("-------------------------------------------");
            System.out.println("getDirection() = " + zzz.getDirection());
            System.out.println("getId() = " + zzz.getId());
            System.out.println("getStatus() = " + zzz.getStatus());
            System.out.println("getStartFloor() = " + zzz.getStartFloor());
            System.out.println("getDestFloor() = " + zzz.getDestFloor());
            System.out.println("-------------------------------------------");
        }

        if (id == 3) {
            waitingList3.add(zzz);
            euiList.get(2).addIDToStringArray(zzz.getId(), zzz.getDestFloor());
            euiList.get(2).updateUsersOnLiftPanel();
            System.out.println("-------------------------------------------");
            System.out.println("getDirection() = " + zzz.getDirection());
            System.out.println("getId() = " + zzz.getId());
            System.out.println("getStatus() = " + zzz.getStatus());
            System.out.println("getStartFloor() = " + zzz.getStartFloor());
            System.out.println("getDestFloor() = " + zzz.getDestFloor());
            System.out.println("-------------------------------------------");

        }
    }

    public void manualCallLift(int startFloor) {

        Random randomGeneratorA = new Random();
        int randy = randomGeneratorA.nextInt(noLifts) + 1;

        int destFloor;
        Random randomGenerator = new Random();
        while (true) {
            destFloor = randomGenerator.nextInt(inQueue.size()) + 1;
            if (startFloor != destFloor) {
                break;
            }
        }
        //Create Person and set attributes
        Person zzz = new Person(startFloor, destFloor);

        if (randy == 1) {
            waitingList1.add(zzz);
            inQueue.get(zzz.getStartFloor() - 1).addIDToStringArray(zzz.getId(), zzz.getDestFloor());
            inQueue.get(zzz.getStartFloor() - 1).incrementWaitingLabel();
            System.out.println("-------------------------------------------");
            System.out.println("getDirection() = " + zzz.getDirection());
            System.out.println("getId() = " + zzz.getId());
            System.out.println("getStatus() = " + zzz.getStatus());
            System.out.println("getStartFloor() = " + zzz.getStartFloor());
            System.out.println("getDestFloor() = " + zzz.getDestFloor());
            System.out.println("-------------------------------------------");
        }
        if (randy == 2) {
            waitingList2.add(zzz);
            inQueue.get(zzz.getStartFloor() - 1).addIDToStringArray(zzz.getId(), zzz.getDestFloor());
            inQueue.get(zzz.getStartFloor() - 1).incrementWaitingLabel();
            System.out.println("-------------------------------------------");
            System.out.println("getDirection() = " + zzz.getDirection());
            System.out.println("getId() = " + zzz.getId());
            System.out.println("getStatus() = " + zzz.getStatus());
            System.out.println("getStartFloor() = " + zzz.getStartFloor());
            System.out.println("getDestFloor() = " + zzz.getDestFloor());
            System.out.println("-------------------------------------------");
        }

        if (randy == 3) {
            waitingList3.add(zzz);
            inQueue.get(zzz.getStartFloor() - 1).addIDToStringArray(zzz.getId(), zzz.getDestFloor());
            inQueue.get(zzz.getStartFloor() - 1).incrementWaitingLabel();
            System.out.println("-------------------------------------------");
            System.out.println("getDirection() = " + zzz.getDirection());
            System.out.println("getId() = " + zzz.getId());
            System.out.println("getStatus() = " + zzz.getStatus());
            System.out.println("getStartFloor() = " + zzz.getStartFloor());
            System.out.println("getDestFloor() = " + zzz.getDestFloor());
            System.out.println("-------------------------------------------");

        }

    }

    public void addPerson() {
        Random randomGenerator1 = new Random();
        if (randomGenerator1.nextInt(100) < addPersonPrabability) {
            int startFloor;
            int destFloor;

            while (true) {
                startFloor = randomGenerator1.nextInt(inQueue.size()) + 1;
                destFloor = randomGenerator1.nextInt(inQueue.size()) + 1;
                if (startFloor != destFloor) {
                    break;
                }
            }

            Person jjj = new Person(startFloor, destFloor);

            waitingList1.add(jjj);
            inQueue.get(jjj.getStartFloor() - 1).addIDToStringArray(jjj.getId(), jjj.getDestFloor());
            inQueue.get(jjj.getStartFloor() - 1).incrementWaitingLabel();

            System.out.println("-------------------------------------------");
            System.out.println("getDirection() = " + jjj.getDirection());
            System.out.println("getId() = " + jjj.getId());
            System.out.println("getStatus() = " + jjj.getStatus());
            System.out.println("getStartFloor() = " + jjj.getStartFloor());
            System.out.println("getDestFloor() = " + jjj.getDestFloor());
            System.out.println("-------------------------------------------");
        }
        if (noLifts >= 2) {
            Random randomGenerator2 = new Random();
            if (randomGenerator2.nextInt(100) < addPersonPrabability) {
                int startFloor;
                int destFloor;

                while (true) {
                    startFloor = randomGenerator2.nextInt(inQueue.size()) + 1;
                    destFloor = randomGenerator2.nextInt(inQueue.size()) + 1;
                    if (startFloor != destFloor) {
                        break;
                    }
                }

                Person kkk = new Person(startFloor, destFloor);
                waitingList2.add(kkk);
                inQueue.get(kkk.getStartFloor() - 1).addIDToStringArray(kkk.getId(), kkk.getDestFloor());
                inQueue.get(kkk.getStartFloor() - 1).incrementWaitingLabel();

                System.out.println("-------------------------------------------");
                System.out.println("getDirection() = " + kkk.getDirection());
                System.out.println("getId() = " + kkk.getId());
                System.out.println("getStatus() = " + kkk.getStatus());
                System.out.println("getStartFloor() = " + kkk.getStartFloor());
                System.out.println("getDestFloor() = " + kkk.getDestFloor());
                System.out.println("-------------------------------------------");
            }
        }
        if (noLifts > 2) {
            Random randomGenerator3 = new Random();
            if (randomGenerator3.nextInt(100) < addPersonPrabability) {
                int startFloor;
                int destFloor;

                while (true) {
                    startFloor = randomGenerator3.nextInt(inQueue.size()) + 1;
                    destFloor = randomGenerator3.nextInt(inQueue.size()) + 1;
                    if (startFloor != destFloor) {
                        break;
                    }
                }

                Person iii = new Person(startFloor, destFloor);
                waitingList3.add(iii);
                inQueue.get(iii.getStartFloor() - 1).addIDToStringArray(iii.getId(), iii.getDestFloor());
                inQueue.get(iii.getStartFloor() - 1).incrementWaitingLabel();

                System.out.println("-------------------------------------------");
                System.out.println("getDirection() = " + iii.getDirection());
                System.out.println("getId() = " + iii.getId());
                System.out.println("getStatus() = " + iii.getStatus());
                System.out.println("getStartFloor() = " + iii.getStartFloor());
                System.out.println("getDestFloor() = " + iii.getDestFloor());
                System.out.println("-------------------------------------------");
            }
        }
    }

    public void setK(int simTimerSec) {
        this.k = simTimerSec;
    }

    public int getK() {
        return this.k;
    }

    public void run() {
        setK(simulationTimerSeconds);
        int manualCycleCount = 0;

        while (getK() > 0) {
            while (alarmFlag) {
                counter++;
                if (counter % 1000000000 == 1) {
                    Toolkit.getDefaultToolkit().beep();
                }
            }
            if (manualCycleCount == 5) {
                for (int i = 0; i < outQueue.size(); i++) {
                    outQueue.get(i).newCycleStringTwoOne();
                    outQueue.get(i).incrementWaitingLabel();
                    manualCycleCount = 0;
                }
            }
            try {
                Thread.sleep(1000);
                setK(getK() - 1);
            } catch (Exception trew) {
            }

            addPerson();

            for (Person p : waitingList1) {
                euiList.get(0).updateLblPanel(shafts[0].getLiftDirection());

                //for (int j = 0; noLifts > j;j++){
                if (shafts[0].getLiftStatus().equals("READY")) {

//                  get everyone who is travelling to this floor off the lift;
                    if (!waitingList1.isEmpty()) {
                        //for (Person p : waitingList) {
                        if (p.getDestFloor() == shafts[0].getLiftFloor()) {
                            if ("TRAV".equals(p.getStatus())) {
                                p.setStatus("OUT");
                                outQueue.get(p.getDestFloor() - 1).createStringTwo(p.getId());
                                outQueue.get(p.getDestFloor() - 1).incrementWaitingLabel();
                                euiList.get(0).removeIDFromLift(p.getId(), p.getDestFloor());
                                euiList.get(0).updateUsersOnLiftPanel();

                                System.out.println(p);

                            }

                        }


//                  get all of waiting queue on this floor onto the lift;
                        if (!waitingList1.isEmpty()) {
                            //for (Person p : waitingList) {
                            if (p.getStartFloor() == shafts[0].getLiftFloor()) {
                                if ("IN".equals(p.status)) {
                                    p.status = "TRAV";
                                    inQueue.get(p.getStartFloor() - 1).removeIDFromLift(p.getId(), p.getDestFloor());
                                    inQueue.get(p.getStartFloor() - 1).decrementWaitingLabel();
                                    euiList.get(0).addIDToStringArray(p.getId(), p.getDestFloor());
                                    euiList.get(0).updateUsersOnLiftPanel();
                                    System.out.println(p);
                                }
                                //}
                            }
                        }
//
//                  determine closest point with same direction to pick up or drop off;
                        if (shafts[0].getLiftDirection() == "DOWN") {
                            boolean y = true;
                            for (int i = shafts[0].getLiftFloor(); i >= 1; i--) {
                                //for (Person p : waitingList) {
                                if ((p.getStartFloor() == i && p.getStatus() == "IN") || (p.getDestFloor() == i && p.getStatus() == "TRAV")) {
                                    shafts[0].callElevator(i - 1);
                                    y = false;
                                    //}
                                }
                            }
                            if (y) {
                                shafts[0].e.setDirection("UP");
                            }
                        }

                        if (shafts[0].getLiftDirection() == "UP") {
                            boolean y = true;
                            for (int i = shafts[0].getLiftFloor(); i <= shafts[0].floors.size(); i++) {
                                // for (Person p : waitingList) {
                                if ((p.getStartFloor() == i && p.getStatus() == "IN") || (p.getDestFloor() == i && p.getStatus() == "TRAV")) {
                                    shafts[0].callElevator(i - 1);
                                    y = false;
                                    //  }
                                }
                            }
                            if (y) {
                                shafts[0].e.setDirection("DOWN");
                            }
                        }

                    }


                }

            }
            for (Person p : waitingList2) {
                euiList.get(1).updateLblPanel(shafts[1].getLiftDirection());

                //for (int j = 0; noLifts > j;j++){
                if (shafts[1].getLiftStatus().equals("READY")) {

//                  get everyone who is travelling to this floor off the lift;
                    if (!waitingList2.isEmpty()) {
                        //for (Person p : waitingList) {
                        if (p.destFloor == shafts[1].getLiftFloor()) {
                            if (p.status.equals("TRAV")) {
                                p.status = "OUT";
                                outQueue.get(p.getDestFloor() - 1).createStringTwo(p.getId());
                                outQueue.get(p.getDestFloor() - 1).incrementWaitingLabel();
                                euiList.get(1).removeIDFromLift(p.getId(), p.getDestFloor());
                                euiList.get(1).updateUsersOnLiftPanel();
                                System.out.println(p);
                                // }
                            }
                            //}
                        }


//                  get all of waiting queue on this floor onto the lift;
                        if (!waitingList2.isEmpty()) {
                            //for (Person p : waitingList) {
                            if (p.startFloor == shafts[1].getLiftFloor()) {
                                if (p.status == "IN") {
                                    p.status = "TRAV";
                                    inQueue.get(p.getStartFloor() - 1).removeIDFromLift(p.getId(), p.getDestFloor());
                                    inQueue.get(p.getStartFloor() - 1).decrementWaitingLabel();
                                    euiList.get(1).addIDToStringArray(p.getId(), p.getDestFloor());
                                    euiList.get(1).updateUsersOnLiftPanel();
                                    System.out.println(p);
                                }
                                //}
                            }
                        }
//
//                  determine closest point with same direction to pick up or drop off;
                        if (shafts[1].getLiftDirection() == "DOWN") {
                            boolean y = true;
                            for (int i = shafts[1].getLiftFloor(); i >= 1; i--) {
                                //for (Person p : waitingList) {
                                if ((p.getStartFloor() == i && p.getStatus() == "IN") || (p.getDestFloor() == i && p.getStatus() == "TRAV")) {
                                    shafts[1].callElevator(i - 1);
                                    y = false;
                                    //}
                                }
                            }
                            if (y) {
                                shafts[1].e.setDirection("UP");
                            }
                        }

                        if (shafts[1].getLiftDirection() == "UP") {
                            boolean y = true;
                            for (int i = shafts[1].getLiftFloor(); i <= shafts[1].floors.size(); i++) {
                                // for (Person p : waitingList) {
                                if ((p.getStartFloor() == i && p.getStatus() == "IN") || (p.getDestFloor() == i && p.getStatus() == "TRAV")) {
                                    shafts[1].callElevator(i - 1);
                                    y = false;
                                    //  }
                                }
                            }
                            if (y) {
                                shafts[1].e.setDirection("DOWN");
                            }
                        }
                    }


                }

            }
            for (Person p : waitingList3) {
                euiList.get(2).updateLblPanel(shafts[2].getLiftDirection());


                //for (int j = 0; noLifts > j;j++){
                if (shafts[2].getLiftStatus().equals("READY")) {

//                  get everyone who is travelling to this floor off the lift;
                    if (!waitingList3.isEmpty()) {
                        //for (Person p : waitingList) {
                        if (p.getDestFloor() == shafts[2].getLiftFloor()) {
                            if (p.getStatus().equals("TRAV")) {
                                p.setStatus("OUT");
                                outQueue.get(p.getDestFloor() - 1).createStringTwo(p.getId());
                                outQueue.get(p.getDestFloor() - 1).incrementWaitingLabel();
                                euiList.get(2).removeIDFromLift(p.getId(), p.getDestFloor());
                                euiList.get(2).updateUsersOnLiftPanel();

                                System.out.println(p);
                                // }
                            }
                            //}
                        }

//                  get all of waiting queue on this floor onto the lift;
                        if (!waitingList3.isEmpty()) {
                            //for (Person p : waitingList) {
                            if (p.startFloor == shafts[2].getLiftFloor()) {
                                if (p.getStatus() == "IN") {
                                    p.setStatus("TRAV");
                                    inQueue.get(p.getStartFloor() - 1).removeIDFromLift(p.getId(), p.getDestFloor());
                                    inQueue.get(p.getStartFloor() - 1).decrementWaitingLabel();
                                    euiList.get(2).addIDToStringArray(p.getId(), p.getDestFloor());
                                    euiList.get(2).updateUsersOnLiftPanel();
                                    System.out.println(p);
                                }
                                //}
                            }
                        }
//
//                  determine closest point with same direction to pick up or drop off;
                        if (shafts[2].getLiftDirection() == "DOWN") {
                            boolean y = true;
                            for (int i = shafts[2].getLiftFloor(); i >= 1; i--) {
                                //for (Person p : waitingList) {
                                if ((p.getStartFloor() == i && p.getStatus() == "IN") || (p.getDestFloor() == i && p.getStatus() == "TRAV")) {
                                    shafts[2].callElevator(i - 1);
                                    y = false;
                                    //}
                                }
                            }
                            if (y) {
                                shafts[2].e.setDirection("UP");
                            }
                        }

                        if (shafts[2].getLiftDirection() == "UP") {
                            boolean y = true;
                            for (int i = shafts[2].getLiftFloor(); i <= shafts[2].floors.size(); i++) {
                                // for (Person p : waitingList) {
                                if ((p.getStartFloor() == i && p.getStatus() == "IN") || (p.getDestFloor() == i && p.getStatus() == "TRAV")) {
                                    shafts[2].callElevator(i - 1);
                                    y = false;
                                    //  }
                                }
                            }
                            if (y) {
                                shafts[2].e.setDirection("DOWN");
                            }
                        }
                    }

                }
            }
            manualCycleCount++;

        }

    }

    public void createElevatorUI() {
        if (eui != null) {
            for (int i = 0; i < euiList.size(); i++) {
                if (euiList.get(i) != null) {
                    euiList.get(i).dispose();
                }
            }
        }
        int count = 345;
        euiList = new ArrayList<ElevatorUI>();
        for (int i = 1; i <= noLifts; i++) {

            eui = new ElevatorUI(this.noFloors, ls.e, this);
            eui.setID(i);
            eui.setTitle("Elevator: #" + i);

            eui.setLocation(count, 0);
            euiList.add(eui);
            count = count + 320;
        }
    }
    

    public void alarmActive() {

        alarmFlag = true;
    }

    public void deactivateAlarm() {
        alarmFlag = false;

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}
